home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Suzy B Software 2
/
Suzy B Software CD-ROM 2 (1994).iso
/
adult_ed
/
rp
/
rp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-02
|
17KB
|
616 lines
/*
rp
Running Performance Predictor
by Joseph M. Knapp
*/
#include <stdio.h>
#include <math.h>
#define MAXEVENTS 50 /* maximum # of events to analyze */
#define MAXSTRING 15 /* maximum length of time string */
#define MAXUSTR 20 /* maximum length of distance-unit strings */
#define MILE 1609 /* meters per mile */
#define MAXU 50 /* maximum number of distance units */
#define UNK -1 /* unknown string flag */
#define AMB -2 /* ambiguous string flag */
#define LOWCORR .90 /* low-correlation message threshold */
#define MAXV0 12 /* maximum v0 before error warning */
#define MINV1 -4 /* minimum v1 before error warning */
#define MAXLINE 80 /* maximum line length in event file */
#define TRUE 1
#define FALSE 0
/* this structure will be used to hold the unit/value pairs */
struct ascfloat {
char string[MAXUSTR] ; /* ascii representation of unit */
float value ; /* value of unit (meters) */
} ;
/* this structure will hold an event read in from the event file */
struct event {
float s ; /* distance of event */
float t ; /* time of event */
} ;
/* this structure will hold the predicted performances */
struct pp {
float logs ; /* log10 of prediction distance */
float v ; /* predicted average speed */
} ;
/* uval() - returns the value of a distance-unit string */
float uval(tunit,utypes,no)
char tunit[] ; /* string containing test unit specification */
struct ascfloat utypes[] ; /* .string, .value pairs */
int no ; /* number of pairs in structure */
{
int uind ; /* index into utypes structure */
uind = strmtch(tunit,utypes,no) ; /* returns index of match or err code */
if (uind == UNK)
{
fprintf(stderr,"distance-file error: '%s' unknown\n",tunit) ;
exit(0) ;
}
else if (uind == AMB)
{
fprintf(stderr,"distance-file error: '%s' ambiguous\n",tunit) ;
exit(0) ;
}
else return(utypes[uind].value) ; /* successful match, return value */
}
/* realtime() take a time string (e.g. 8:20:13) and returns the value in sec */
double realtime(str)
char *str ; /* time string */
{
char *sptr ; /* pointer into substring */
char substr[MAXSTRING] ; /* substring */
static int level ; /* 0=sec 1=min 2=hr */
static float cumtime ; /* cumulative time */
double realtime() ; /* recursive */
float tfield ; /* value of time field */
sptr = substr ; /* point to substring (now empty) */
level = 0 ;
cumtime = 0 ;
/* copy time string into substr[] until ':' or end of string */
while ((*sptr = *str) != '\0' &&
*str != ':' )
{
sptr++ ;
str++ ;
}
/* if now pointing to ':' ther are more fields, call again */
if (*sptr == ':') cumtime = realtime(++str) ;
/* bottomed out, ripple back */
*sptr = '\0' ;
if (sscanf(substr,"%f",&tfield))
{
return(cumtime + tfield * pow((double)60,(double)(level++))) ;
}
else
{
fprintf(stderr,"event-file error: bad time string\n") ;
exit(0) ;
}
}
/* return TRUE if line is not a comment */
int comf(tline)
char *tline ;
{
char ch ;
sscanf(tline," %c ",&ch) ;
if (ch == '*') return(FALSE) ;
else return(TRUE) ;
}
/* return TRUE if line is not all whitespace */
int notwhite(tline)
char *tline ;
{
int wflg ;
int ich ;
wflg = FALSE ;
for (ich = 0 ; ich < strlen(tline) ; ich++)
if (!isspace(*(tline+ich))) wflg = TRUE ;
return(wflg) ;
}
usage()
{
printf("\nusage:\n") ;
printf("rp [-q|-12][-d <dist-file>][-u <unit-file>] [<event-file>]\n") ;
printf(" where:\n") ;
printf(" <events> is a file of events:<distance><time> pairs\n") ;
printf(" e.g., 10 k 36:16 * this is a comment\n") ;
printf(" <unit-file> is a file of known distance units\n") ;
printf(" where a unit is a <string> <meters> pair\n") ;
printf(" e.g., miles 1609\n") ;
printf(" (default file: dunits)\n") ;
printf(" <dist-file> is a file of prediction distances\n") ;
printf(" where a distance is a <number> <unit> pair\n") ;
printf(" e.g., 0.5 marathon\n") ;
printf(" (default file: dlist)\n") ;
printf(" -12 -> simulate a 12-minute fitness test\n") ;
printf(" -q -> print list of runs of same quality as a\n") ;
printf(" specified standard run\n\n") ;
printf("\n rp without args reads events from keyboard\n") ;
exit(0) ;
}
main(argc,argv)
int argc ;
char *argv[] ;
{
FILE *fp, *fopen() ;
struct event events[MAXEVENTS] ; /* distance/time pairs */
struct pp perfline[MAXEVENTS] ; /* speed/log-distance pairs */
float vbar ; /* average speed of events */
float v0 ;
float sbar ; /* average ditance of events */
char time[MAXSTRING] ; /* time string xx:xx:xx.x */
char unit[MAXSTRING] ; /* distance unit */
float scalar ; /* scalar distance */
int eventno ; /* event counter */
int ev ;
int stdineof ;
int nunits ;
int option, optind ;
int age, isex ;
char sex[10] ;
float cvar ;
float var1 ;
float var2 ;
float m12, m21 ;
float b12, b21 ;
float rho ;
float s, v, t ;
float smx, smn ;
char ufile[50], dfile[50], pfile[50] ;
char evline[MAXLINE] ;
float uval() ;
double realtime() ;
struct ascfloat utypes[MAXU] ;
sprintf(ufile,"%s","dunits") ;
sprintf(dfile,"%s","dlist") ;
/* process command-line options */
option = 0 ;
for (optind = 1 ; optind < argc-1 ; optind++)
{
if (strcmp(argv[optind],"-12" ) == 0) option = 1 ;
else if (strcmp(argv[optind],"-q" ) == 0) option = 2 ;
else if (strcmp(argv[optind],"-u") == 0)
sprintf(ufile,"%s",argv[++optind]) ;
else if (strcmp(argv[optind],"-d") == 0)
sprintf(dfile,"%s",argv[++optind]) ;
else if (strcmp(argv[optind],"-h") == 0)
usage() ;
else
{
printf("unknown option '%s'\n",argv[optind]) ;
usage() ;
exit(0) ;
}
}
nunits = uload(ufile,utypes) ; /* load unit file into 'utypes' struct */
/* get fp of event file */
if (argc > 1)
{
sprintf(pfile,"%s",argv[argc-1]) ;
fp = fopen(pfile,"r") ;
if (fp == NULL)
{
fprintf(stderr,"event-file error: can't open '%s'\n",pfile) ;
exit(0) ;
}
}
else
{
fp=stdin ; /* only one arg, use stdin */
sprintf(pfile,"%s","stdin") ;
}
/* get events and store them in 'events' struct */
eventno = 0 ;
stdineof = 1 ; /* will go to 0 on empty line from stdin */
if (fp == stdin)
printf("enter events: <distance> <time> , end with empty line\n") ;
while ((fp != stdin || stdineof) && fgets(evline,MAXLINE,fp) != NULL)
{
/* skip if comment */
if(comf(evline))
{
if (*evline != '\n') /* only do if length > 0 */
{
/* read event line and check for scanf format error */
if (notwhite(evline)) /* is not all whitespace? */
{
if (sscanf(evline," %f %s %s ",&scalar,unit,time))
{
events[eventno].s = scalar * uval(unit,utypes,nunits) ;
events[eventno].t = realtime(time) ;
eventno++ ;
}
else
{
fprintf(stderr,"event-file error: field 1 not a number\n") ;
exit(0) ;
}
}
}
else stdineof = 0 ; /* if length = 0 terminate stdin */
}
}
if (fp != stdin) fclose(fp) ;
if (eventno < 2)
{
fprintf(stderr,"event-file error: not enough events\n") ;
exit(0) ;
}
smx = 0 ;
smn = 1e6 ;
for (ev = 0 ; ev < eventno ; ev++)
{
s = events[ev].s ;
if (s < smn) smn = s ;
if (s > smx) smx = s ;
}
if (smx - smn == 0)
{
fprintf(stderr,"event-file error: all events are same distance\n") ;
exit(0) ;
}
for (ev = 0; ev < eventno; ev++)
{
perfline[ev].v = events[ev].s/events[ev].t ;
perfline[ev].logs = log10(events[ev].s) ;
}
vbar = 0 ;
sbar = 0 ;
for (ev = 0 ; ev < eventno ; ev++)
{
vbar += perfline[ev].v ;
sbar += perfline[ev].logs ;
}
vbar = vbar/eventno ;
sbar = sbar/eventno ;
cvar = 0 ;
for (ev = 0 ; ev < eventno ; ev++)
cvar += (perfline[ev].v - vbar) * (perfline[ev].logs - sbar) ;
cvar = cvar/(eventno - 1) ;
var1 = 0 ;
var2 = 0 ;
for (ev = 0 ; ev < eventno ; ev++)
{
var1 += (perfline[ev].logs - sbar) * (perfline[ev].logs - sbar) ;
var2 += (perfline[ev].v - vbar) * (perfline[ev].v - vbar) ;
}
var1 = var1/(eventno - 1) ;
var2 = var2/(eventno - 1) ;
m12 = var2/cvar ;
b12 = vbar - m12 * sbar ;
m21 = cvar/var1 ;
b21 = vbar - m21 * sbar ;
rho = cvar/(sqrt(var1)*sqrt(var2)) ;
switch(option) {
case 0:
grid(b21,m21,dfile,utypes,nunits,rho,pfile,eventno) ;
break ;
case 1:
printf("\n>>> 12-Minute Fitness Test (after Dr. Kenneth Cooper) <<<\n") ;
printf("\n") ;
do
{
printf("enter sex (m/f): ") ;
scanf("%s",sex) ;
}
while (sex[0] != 'm' && sex[0] !='f') ;
if (sex[0] == 'm') isex=0 ;
else isex=1 ;
do
{
printf("input age: ") ;
scanf("%d",&age) ;
}
while (age < 1 || age > 99) ;
test12(b21,m21,isex,age) ;
break ;
case 2:
printf("Input standard run <distance> <time>: ") ;
scanf(" %f %s %s ", &scalar, unit, time) ;
t = realtime(time) ;
s = scalar * uval(unit,utypes,nunits) ;
v = s/t ;
v0 = b21 + m21*log10(s) - v ;
grid(b21-v0,m21,dfile,utypes,nunits,rho,pfile,eventno) ;
}
}
grid(b,m,dfile,utypes,nunits,rho,pfile,no)
char dfile[] ;
struct ascfloat utypes[] ;
int nunits ;
float b,m,rho ;
char pfile[] ;
int no ;
{
FILE *fp, *fopen() ;
float s,v,t ;
float scalar ;
char pace[20],
time[20] ;
char unit[20] ;
float uval() ;
int scanres ;
fp = fopen(dfile,"r") ; /* open distance-list file */
if (fp == NULL)
{
fprintf(stderr,"distance-file error: can't open '%s'\n",dfile) ;
exit(0) ;
}
printf("\nanalysis of file '%s' (%d events):\n",pfile,no) ;
printf("\nmodel equation: v =%5.2f%6.2f*log10(s)",b,m) ;
if (no > 2) printf(" correlation ~ %2.0f\n",fabs(rho*100.)) ;
else printf("\n") ;
if ( b > MAXV0 || m > 0 || m < MINV1 )
printf("probable bogus model -- unusual parameters\n") ;
if (fabs(rho) < LOWCORR)
printf("low correlation\n") ;
printf("\n") ;
printf("%-19s %10s %10s %10s\n"," ",
"time","speed","pace") ;
printf("%-19s %10s %10s %10s\n","distance",
"hh:mm:ss","meters/s","min/mile") ;
printf("%-19s %10s %10s %10s\n","-----------------",
"--------","--------","--------") ;
while ((scanres = fscanf(fp," %f %s ",&scalar,unit)) != EOF )
{
if (!scanres)
{
fprintf(stderr,"distance-file error: unrecognizable distance\n") ;
exit(0) ;
}
s = scalar * uval(unit,utypes,nunits) ;
v = b + m*log10(s) ;
t = s/v ;
tstr(MILE/v,pace) ;
tstr(t,time) ;
if (fmod(scalar,1.0) > 0)
printf("%6.1f %-12s %10s %10.2f %10s\n",
scalar,unit,time,v,pace) ;
else
printf("%6.0f %-12s %10s %10.2f %10s\n",
scalar,unit,time,v,pace) ;
}
printf("\n") ;
fclose(fp) ;
}
tstr(t,str)
float t ;
char *str ;
{
int h,m,s ;
int it ;
it = t ;
h = it / 3600 ;
m = (it/60)-h*60 ;
s = it - h*3600 - m*60 ;
if (h>0)
sprintf(str,"%2d:%02d:%02d",h,m,s) ;
else {
if (m>0)
sprintf(str,"%2d:%02d",m,s) ;
else
sprintf(str,"%2d",s) ;
}
}
/* return position of matching string or UNK (unknown) or AMB (ambiguous) */
strmtch(ustr,utypes,no)
char *ustr ; /* test string */
struct ascfloat utypes[] ; /* reference unit strings (& values) */
int no ; /* number of reference strings */
{
int m, nmatch ;
int word, len, imtch ;
nmatch = 0 ;
word = 0 ;
len = strlen(ustr) ;
do
{
m = strncmp(ustr,utypes[word++].string,len) ;
if (m == 0)
{
nmatch++ ;
imtch = word - 1 ;
}
}
while (word < no) ;
if (nmatch > 1) word = AMB ;
else if (nmatch == 0) word = UNK ;
else word = imtch ;
return(word) ;
}
int uload(ufile,utypes)
char ufile[] ; /* file containing <string> <meters> pairs */
struct ascfloat utypes[] ; /* to contain those pairs */
{
int i ;
int scanres ;
FILE *fp, *fopen() ;
fp = fopen(ufile,"r") ;
if (fp == NULL)
{
fprintf(stderr,"unit-file error: can't open '%s'\n",ufile) ;
exit(0) ;
}
i = 0 ;
while ((scanres=fscanf(fp," %s %f ",utypes[i].string,&utypes[i].value))!=EOF)
{
i++ ;
if (!scanres)
{
fprintf(stderr,"unit-file error: illegal unit definition \n") ;
exit(0) ;
}
}
fclose(fp) ;
if (i == 0)
{
fprintf(stderr,"unit-file error: no units recognized in '%s'\n",ufile) ;
exit(0) ;
}
return(i) ;
}
test12(v0,v1,sex,age)
float v0 ; /* one-meter speed */
float v1 ; /* aerobic factor */
int sex ; /* 0=male 1=female */
int age ; /* years old */
{
static float mu30[6] = { 0.00,1.00, 1.24, 1.49, 1.74, 3.5 } ;
static float mu40[6] = { 0.00,0.95, 1.14, 1.39, 1.64, 3.5 } ;
static float mu50[6] = { 0.00,0.85, 1.04, 1.29, 1.54, 3.5 } ;
static float mu99[6] = { 0.00,0.80, 0.99, 1.24, 1.49, 3.5 } ;
static float wu30[6] = { 0.00,0.95, 1.14, 1.34, 1.64, 3.5 } ;
static float wu40[6] = { 0.00,0.85, 1.04, 1.24, 1.54, 3.5 } ;
static float wu50[6] = { 0.00,0.75, 0.94, 1.14, 1.44, 3.5 } ;
static float wu99[6] = { 0.00,0.65, 0.84, 1.04, 1.34, 3.5 } ;
static float *man[4] = { mu30, mu40, mu50, mu99 } ;
static float *woman[4] = { wu30, wu40, wu50, wu99 } ;
static float vo2tab[6] = { 0.00,25.0,33.7,42.5,51.5,105.0 } ;
static float stab[6] = { 0,1.0,1.25,1.50,1.75,3.5 } ;
int ageind ;
int level ;
int vind ;
float minv,maxv ;
float s ;
float maxvo2, x ;
level = 0 ;
ageind = age/10 - 2 ;
if (ageind < 0 ) ageind = 0 ;
/* calculate 12-minute distance in miles */
s = 160 ; /* 160 meters = 0.1 mile */
while (s/(v0+v1*log10(s)) < 720 )
s = s + 160 ;
while (s/(v0 + v1*log10(s)) > 720 )
s = s - 16 ;
/* convert meters to miles */
s = s/(MILE) ;
/* find fitness level (1-5) */
if (sex == 0 ) /* woman */
while (woman[ageind][level++] < s) ;
else
while (man[ageind][level++] < s) ;
level-- ; /* correct level */
/* interpolate to find max V02 */
vind = 0 ;
while(stab[vind] < s ) vind++;
vind-- ;
minv = vo2tab[vind] ;
maxv = vo2tab[vind + 1] ;
x = (s - stab[vind])/(stab[vind+1]-stab[vind]) ;
maxvo2 = minv + x*(maxv-minv) ;
printf("\nIn 12 minutes, you could run%5.2f miles.\n\n",s) ;
printf("Of very poor, poor, fair, good, and excellent,\n") ;
printf("your fitness level is " ) ;
switch(level) {
case 1:
printf( "very poor.\n\n") ;
break ;
case 2:
printf( "poor.\n\n" );
break ;
case 3:
printf( "fair.\n\n" );
break ;
case 4:
printf( "good.\n\n" );
break ;
case 5:
printf( "excellent.\n\n") ;
break ;
}
printf("Your estimated maximum oxygen uptake (VO2max)\n") ;
printf("is%5.1f ml/kg/min.\n\n", maxvo2) ;
}